package com.dq.jingran.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dq.jingran.entity.JrUser;
import com.dq.jingran.exception.ExceptionVo;
import com.dq.jingran.mapper.JrUserMapper;
import com.dq.jingran.service.JrUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dq.jingran.utils.JWTUtils;
import com.dq.jingran.utils.UserPropertiesUtils;
import com.dq.jingran.utils.UserThreadLocal;
import com.dq.jingran.vo.space.SpaceUserVo;
import com.dq.jingran.vo.user.ChangeUserNameParams;
import com.dq.jingran.vo.user.UpdatePassParams;
import com.dq.jingran.vo.user.UserParams;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * (JrUser)表服务实现类
 *
 * @author Dq
 * @since 2022-09-19 17:44:03
 */
@Service
@Slf4j
public class JrUserServiceImpl extends ServiceImpl<JrUserMapper, JrUser> implements JrUserService {
    private static final String salt = "Dq333";

    @Autowired
    private JrUserMapper userMapper;
    @Resource
    private UserPropertiesUtils userPropertiesUtils;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    //用户注册 OOS  only online sigel  单点登录
    @Override
    public String registerUser(UserParams user) {
        String username = user.getUsername();
        String password = user.getPassword();
        if (username.isEmpty() || password.isEmpty()) {
            throw new ExceptionVo(20001, "用户或密码不能为空,请重新输入新的账户密码");
        }
        //加密
        password = DigestUtils.md5Hex(password);

        LambdaQueryWrapper<JrUser> jrUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        jrUserLambdaQueryWrapper.eq(JrUser::getUsername,username)
                .eq(JrUser::getPassword,password);
        Integer selectCount = userMapper.selectCount(jrUserLambdaQueryWrapper);
        if (selectCount>=1){
            throw new ExceptionVo(20001,"该用户已被注册");
        }
        //插入用户
        JrUser jrUser = new JrUser();
        jrUser.setUsername(username);
        jrUser.setPassword(password);
        jrUser.setAvatar("https://jing-ran-1310347558.cos.ap-chengdu.myqcloud.com/%E5%A4%A7%E7%99%BD%E7%86%8A.jpg");
        userMapper.insert(jrUser);
        //生成token令牌
        String id = jrUser.getId();
        String token = JWTUtils.createToken(id);
        //保存在redis  1天
        System.out.println(jrUser);
        redisTemplate.opsForValue().set("TOKEN-"+token, JSON.toJSONString(jrUser),1, TimeUnit.DAYS);
        return token;
    }

    //用户登录
    @Override
    public String login(UserParams userParams) {
        String password = userParams.getPassword();
        String username = userParams.getUsername();
        if (username.isEmpty() || password.isEmpty()) {
            throw new ExceptionVo(20001, "用户或密码不能为空");
        }
        //加密  md5e751fe9b0dd64eb875f67c01299e94c9
        password = DigestUtils.md5Hex(password);

        LambdaQueryWrapper<JrUser> jrUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        jrUserLambdaQueryWrapper.eq(JrUser::getUsername,username)
                .eq(JrUser::getPassword,password);

        JrUser jrUser = userMapper.selectOne(jrUserLambdaQueryWrapper);
        if (jrUser==null){
            throw new ExceptionVo(20001,"用户名或账号错误，请重新输入");
        }
        String id = jrUser.getId();
        String token = JWTUtils.createToken(id); //密文
        //保存在redis  1天
        System.out.println(jrUser);
        redisTemplate.opsForValue().set("TOKEN-"+token, JSON.toJSONString(jrUser),1, TimeUnit.DAYS);
        return token;
    }

    //校验数据
    @Override
    public JrUser checkTokenAndReturnData(String token) {
        JrUser user=checkToken(token);
        return user;
    }

    //获取用于空间数据的基本信息
    @Override
    public SpaceUserVo getSomeInfoToSpace(String userId) {
        LambdaQueryWrapper<JrUser> jrUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        jrUserLambdaQueryWrapper.eq(JrUser::getId,userId)
                .select(JrUser::getId,JrUser::getUsername,JrUser::getAvatar);
        JrUser jrUser = userMapper.selectOne(jrUserLambdaQueryWrapper);
        SpaceUserVo userVo = copy(jrUser);
        return userVo;
    }

    //修改用户密码
    @Override
    public void updatePass(UpdatePassParams userParams) {

        JrUser user = userMapper.selectById(userParams.getUserId());
        String oldPass = DigestUtils.md5Hex(userParams.getOldPassword());
        if (!oldPass.equals(user.getPassword())){
            throw new ExceptionVo(403,"旧密码错误");
        }

        JrUser jrUser = new JrUser();
        jrUser.setId(userParams.getUserId());
        String password = DigestUtils.md5Hex(userParams.getPassword());
        jrUser.setPassword(password);
        userMapper.updateById(jrUser);

    }

    //上传用户头像
    @Override
    public String upImgToTencentOss(String auth, MultipartFile file) {
        try {
            JrUser jrUser = checkToken(auth);
            COSClient cosClient = getCosClient();


            /**
             * 1. 获取流
             * 2. 拼接name  uuid 。jpg
             * 3. 设置size 节约空间
             * 4. 设置请求体
             * 5. 发送最终上传指令
             */

            InputStream inputStream = file.getInputStream();
            String filename = file.getOriginalFilename();
            String pic = UUID.randomUUID().toString().replace("-", ""); //UUID
            String picName = file.getOriginalFilename(); //文件名称 用于获取后缀名
            String nowDate = new DateTime().toString("yyyy/MM/dd");
            assert picName != null;
            // 1. /avatar/   2. 2022/7/20  3. /  4. 011619125c53add6%21400x400  5. .jpg
            String picUrlNameAndType = userPropertiesUtils.getPrefix()+nowDate +"/"+ pic + picName.substring(picName.lastIndexOf("."));
            //设置流的大小
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(file.getSize());
            //设置对象
            PutObjectRequest putObjectRequest = new PutObjectRequest(userPropertiesUtils.getBucketName(), picUrlNameAndType, inputStream, objectMetadata);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            //关闭
            cosClient.shutdown();

            //统一返回 此路径规则：https://guli-dq-1310347558.cos.ap-chengdu.myqcloud.com/guli/011619125c53add6%21400x400.jpg
            String ResultUrl = userPropertiesUtils.getUrl() + picUrlNameAndType;

            //在此之前进行mapper层的数据存储
            jrUser.setAvatar(ResultUrl);
            userMapper.updateById(jrUser);
            return ResultUrl;

        } catch (Exception e) {
            throw new ExceptionVo(401,"OSS Error");
        }
    }

    //修改名称
    @Override
    public void changeName(ChangeUserNameParams userParams) {
        LambdaQueryWrapper<JrUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JrUser::getId,userParams.getUserId()).select(JrUser::getId);
        JrUser jrUser = userMapper.selectOne(queryWrapper);
        if (jrUser==null){
            throw new ExceptionVo(405,"用户id不存在 请检查是否正确");
        }
        JrUser user = new JrUser();
        user.setId(userParams.getUserId());
        user.setUsername(userParams.getUserName());
        userMapper.updateById(user);
    }

    //获取最新数据
    @Override
    public JrUser getNew(String token) {
        Map<String, Object> map = JWTUtils.checkToken(token);
        String id = (String) map.get("id");
        JrUser jrUser = userMapper.selectById(id);
        return jrUser;
    }


    /**
     * 初始化CosClient相关配置， appid、accessKey、secretKey、region
     *
     * @return
     */
    public COSClient getCosClient() {
        // 1 初始化用户身份信息(secretId, secretKey)
        COSCredentials cred = new BasicCOSCredentials(userPropertiesUtils.getSecretId(), userPropertiesUtils.getSecretKey());
        ClientConfig clientConfig = new ClientConfig(new Region(userPropertiesUtils.getRegion()));
        // 3 生成cos客户端
        COSClient cosClient = new COSClient(cred, clientConfig);
        return cosClient;
    }



    //校验此token
    private JrUser checkToken(String token) {
        if (token.isEmpty()){
            throw new ExceptionVo(20002,"请求头auth参数为空");
        }
        Map<String, Object> map = JWTUtils.checkToken(token);

        if (map==null){
            throw new ExceptionVo(20002,"token格式错误，请检查");
        }
        String id = (String) map.get("id");
        if (id.isEmpty()){
            throw new ExceptionVo(20002,"token格式错误，请检查 id");
        }
        //检验redis中数据是否过期  解析此user对象
        String userInfo_Type = redisTemplate.opsForValue().get("TOKEN-" + token);
        if (StringUtils.isEmpty(userInfo_Type)){
            throw new ExceptionVo(20001,"此token过期 请重新登录");
        }
        if (UserThreadLocal.get() !=null){
            log.info("======================into ThreadLocal");
            return UserThreadLocal.get();
        }
        JrUser jrUser = JSON.parseObject(userInfo_Type, JrUser.class);
        jrUser.setPassword(null);
        return jrUser;
    }


    public SpaceUserVo copy(JrUser user){
        SpaceUserVo userVo = new SpaceUserVo();
        BeanUtils.copyProperties(user,userVo);
        return userVo;
    }
}